package com.tmt.datatable.editor.impl;

import com.tmt.datatable.editor.IFieldMappingHandlerProxy;
import com.tmt.datatable.editor.IFieldValueSetter;
import com.tmt.datatable.editor.instance.IObjectInstanceProxy;
import com.tmt.datatable.editor.instance.impl.DefaultInstanceFactory;
import com.tmt.datatable.editor.instance.impl.ListInstancer;
import com.tmt.datatable.editor.instance.impl.MapInstancer;
import com.tmt.helper.ReflectHelper;
import com.tmt.helper.StringHelper;

import java.util.*;

/**
 * Created by ThreeManTeam on 2017/6/5.
 */
public class DefaultFieldValueSetter implements IFieldValueSetter {

    private IObjectInstanceProxy objectInstanceProxy = null;

    private IFieldMappingHandlerProxy handlerProxy= null;

    public DefaultFieldValueSetter(){
    }

    public DefaultFieldValueSetter(IObjectInstanceProxy objectInstanceProxy,
                                   IFieldMappingHandlerProxy handlerProxy){
        this.objectInstanceProxy = objectInstanceProxy;
        this.handlerProxy = handlerProxy;
    }

    public void defaultInitial(){
        DefaultInstanceFactory instanceFactory = new DefaultInstanceFactory();
        instanceFactory.addInstancer(new ListInstancer());
        instanceFactory.addInstancer(new MapInstancer());

        DefaultFieldMappingHandlerProxy handlerProxy = new DefaultFieldMappingHandlerProxy();

        setObjectInstanceProxy(instanceFactory);
        setHandlerProxy(handlerProxy);
    }

    public IObjectInstanceProxy getObjectInstanceProxy() {
        return objectInstanceProxy;
    }

    public void setObjectInstanceProxy(IObjectInstanceProxy objectInstanceProxy) {
        this.objectInstanceProxy = objectInstanceProxy;
    }

    public IFieldMappingHandlerProxy getHandlerProxy() {
        return handlerProxy;
    }

    public void setHandlerProxy(IFieldMappingHandlerProxy handlerProxy) {
        this.handlerProxy = handlerProxy;
    }

    @Override
    public <T> T setFieldValue(T object, String propPath, Object value, String action) {
        if (object == null || propPath == null || propPath.trim().length() <= 0)
            return null;

        Map<String, Object> newRootPropObjectMap = new HashMap<>();
        Object propObj = instanceFieldObject(object, propPath, newRootPropObjectMap);
        if (propObj == null || propObj.getClass().isPrimitive() || propObj.getClass() == String.class)
            return object;

        String[] infos = propPath.split("\\.");
        String propName = infos[infos.length - 1];

        try {
            //获取有效的字段名称。
            propName = handlerProxy.getValidFieldName(propObj.getClass(), propName, value, action);

            //设置属性对象的值。
            setPropValueByPropPath(propObj, propName, value);

        }catch (Exception ex){
            //如果在设置属性值的过程中异常了，则要清除本次instanceFieldObject方法调用新创建的对象链！
            if (!newRootPropObjectMap.isEmpty()){
                for (String rootPropName : newRootPropObjectMap.keySet()) {
                    Object parentObj = newRootPropObjectMap.get(rootPropName);
                    ReflectHelper.setFieldValue(parentObj, rootPropName, null);
                }
            }
        }

        return object;
    }

    private <T> void setPropValueByPropPath(Object propObj, String propPath, Object value) throws Exception {
        //确定对象和属性。
        String[] paths = propPath.split("\\.");
        String propName = propPath;
        if (paths.length > 1) {
            String tmpPath = propPath.replace("." + paths[paths.length - 1], "");
            propObj = ReflectHelper.getPropObjectByPropPath(propObj, tmpPath);
            propName = paths[paths.length - 1];
        }

        //读取属性路径上最有一个属性的类型。
        Class clazz = ReflectHelper.getFieldClassByFieldName(propObj.getClass(), propName);

        Object validValue = null;
        if (Collection.class.isAssignableFrom(clazz)){
            Class paramClazz = ReflectHelper.getActualClassByFieldName(propObj.getClass(), propName);
            if (value instanceof String[]){
                validValue = StringHelper.stringArrayToList((String[])value, clazz, paramClazz);
            }else {
                validValue = StringHelper.stringToList(value, clazz, paramClazz);
            }
        }else {
            validValue = StringHelper.convertTo(value, clazz);
        }

        //设置属性对象的字段值
        ReflectHelper.setFieldValue(propObj, propName, validValue);
    }

    @Override
    public IFieldMappingHandlerProxy getFieldMappingHandlerProxy() {
        return handlerProxy;
    }


    /**
     * 实例化对象的某个属性。
     * @param object
     * @param propPath
     * @param newRootPropObjectMap 新创建的属性链的根对象所在的父级对象及其在父级对象上的属性名称。用来方便清除本次创建的对象链
     * @param <T>
     * @return
     */
    private <T> Object instanceFieldObject(T object, String propPath, Map<String, Object> newRootPropObjectMap) {
        if (propPath.split("\\.").length <= 1)
            return object;

        String[] propArray = propPath.trim().split("\\.");

        Object propObj = objectInstanceProxy.newInstance(object, propArray[0], newRootPropObjectMap);
        if (propObj == null || propObj.getClass().isPrimitive() || propObj.getClass() == String.class)
            return propObj;

        String[] curPropArray = propArray[0].split("\\[");
        String curProp = curPropArray[0];
        int index = -1;
        if (curPropArray.length > 1)
            index = Integer.parseInt(curPropArray[1].split("]")[0]);

        Object obj = ReflectHelper.getFieldValue(object, curProp);
        if (obj == null) {
            ReflectHelper.setFieldValue(object, curProp, propObj);
        } else if (Collection.class.isAssignableFrom(obj.getClass()) && index >= 0){
            List list = (List) obj;
            propObj = list.get(index);
        } else {
            propObj = obj;
        }

        propPath = propPath.substring(propArray[0].length() + 1);
        return instanceFieldObject(propObj, propPath, newRootPropObjectMap);
    }

}
